package me.luger.project.fof.controller.api;

import com.alibaba.fastjson.JSONObject;
import me.luger.core.auth.cookie.annotation.CookieAuth;
import me.luger.core.auth.cookie.annotation.IgnoreCookieAuth;
import me.luger.core.commom.util.*;
import me.luger.core.dao.nutz.entity.page.Pagination;
import me.luger.core.mvc.controller.BaseController;
import me.luger.core.mvc.entity.IntCodeResult;
import me.luger.core.mvc.entity.Result;
import me.luger.project.fof.entity.*;
import me.luger.project.fof.entity.ext.TaskParams;
import me.luger.project.fof.service.*;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.io.File;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.*;

/**
 * FofInfo controller
 */
@Controller
@RequestMapping("/api/fof/fofInfo")
@CookieAuth
public class FofInfoApiController extends BaseController {

    public static final String  ASSET_STRATEGY_RESULT_PATH  = "/data/fof/matlabFile/AssetAlloc_v2/";

    @Autowired
    private Environment env;

    @Autowired
    private FofInfoService fofInfoService;

    @Autowired
    private ProductTypeService productTypeService;

    @Autowired
    private AssetStrategyInfoService assetStrategyInfoService;

    @Autowired
    private BenchmarkService benchmarkService;

    @Autowired
    private FofTaskService fofTaskService;

    @Autowired
    private FundInfoService fundInfoService;

    @Autowired
    private BenchmarkPriceService benchmarkPriceService;

    @Autowired
    private FundNavService fundNavService;

    @Autowired
    private FofResultService fofResultService;

    @Autowired
    private FofUserService fofUserService;

    @Autowired
    private FofParamHistoyService fofParamHistoyService;

    @RequestMapping(value = "/userFof/{userId}", name = "获取某一用户创建FOF list",method = RequestMethod.GET)
    @ResponseBody
    public Object userFof(@PathVariable Integer userId,
                          @RequestParam(defaultValue = "0") Integer type,
                          @RequestParam(defaultValue = "1") Integer pn,
                          @RequestParam(defaultValue = "50") Integer rn) {
        Map<String, Object> result = null;
        try {
            result = new HashMap<String, Object>();
            Pagination<FofInfo> fofInfoPagination = null;
//            if(type == 0){
//                fofInfoPagination = fofInfoService.getUserAllFof(userId,pn,rn);
//            }else{
            fofInfoPagination = fofInfoService.getUserFofByType(userId,type,pn,rn);
//            }
            result.put("fofListPage", fofInfoPagination);
            result.put("type",type);
//            result.put("productType", productTypeService.getAllType());
        } catch (Exception e) {
            LogUtil.errorLog(e,"");
            return Result.error();
        }
        return Result.success(result);
    }

    /**
     * {"fundList":[{"id":"000575.OF","weight":"61.97%"},{"id":"003968.OF","weight":"38.03%"},{"id":"519567.OF","weight":"0%"},{"id":"001498.OF","weight":"&nbsp;"}]}
     * @param params
     * @return
     */
    @RequestMapping(value = "/create", name = "接口描述")
    @ResponseBody
    @IgnoreCookieAuth
    public Object create(String params,String uid) {
        if(StringUtil.isBlank(uid) || !StringUtil.isNumeric(uid)){
            return Result.error("传入用户ID错误",null);
        }
        Map<String, Object> result = new HashedMap();
        try {
            params = URLDecoder.decode(params);
            JSONObject jsonObject = JsonUtil.parse2JsonObject(params);
            jsonObject = jsonObject.getJSONObject("step5");
            if(null == jsonObject || jsonObject.size() == 0){
                return Result.error("step5的参数为空",null);
            }

            JSONObject jsonObjectStep2 = jsonObject.getJSONObject("step2");
            if(null == jsonObjectStep2 || jsonObjectStep2.size() == 0){
                return Result.error("step2的参数为空",null);
            }
            Double scale = jsonObjectStep2.getDouble("scale");

            String fofName = jsonObject.getString("fofName");
            FofInfo fofInfo = new FofInfo();
            fofInfo.setUserId(Integer.parseInt(uid));
            fofInfo.setFullName(fofName);
            fofInfo.setShortName(fofName);
            fofInfo.setProductType(1);
            fofInfo.setStatus(4);
            fofInfo.setMarketWorth(scale);
            fofInfo.setCreateDate(DateUtil.nowAsDate());
            fofInfo = fofInfoService.insertFofInfo(fofInfo);
            Integer fofId = fofInfo.getId();
            IntCodeResult saveParamResult = fofParamHistoyService.save(fofId,params);
            IntCodeResult intCodeResult = IntCodeResult.error("");
            if(saveParamResult.isSuccess()){
                intCodeResult = fofResultService.saveFofResult(fofId,params,Integer.parseInt(saveParamResult.getExtVal("paramHistoryId").toString()));
            }else{
                return Result.error("saveParamResult error",null);
            }

            if(!intCodeResult.isSuccess() || !saveParamResult.isSuccess()){
                return Result.setIntCodeResult(intCodeResult);
            }

            result.put("fofId", fofInfo.getId());
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("未知错误",null);
        }
        return Result.success(result);
    }

    /**
     * {"fundList":[{"id":"000575.OF","weight":"61.97%"},{"id":"003968.OF","weight":"38.03%"},{"id":"519567.OF","weight":"0%"},{"id":"001498.OF","weight":"&nbsp;"}]}
     * @param params
     * @return
     */
    @RequestMapping(value = "/update", name = "接口描述")
    @ResponseBody
    @IgnoreCookieAuth
    public Object update(String params,String uid) {
        if(StringUtil.isBlank(uid) || !StringUtil.isNumeric(uid)){
            return Result.error("传入用户ID错误",null);
        }
        Map<String, Object> result = new HashedMap();
        try {
            params = URLDecoder.decode(params);
            JSONObject jsonObject = JsonUtil.parse2JsonObject(params);

            Integer fofId = jsonObject.getInteger("fofId");
            if(null == fofId || fofId <= 0){
                return Result.error("fofId错误",null);
            }

            jsonObject = jsonObject.getJSONObject("step5");
            if(null == jsonObject || jsonObject.size() == 0){
                return Result.error("step5的参数为空",null);
            }

            String fofName = jsonObject.getString("fofName");
            FofInfo fofInfo = new FofInfo();
            fofInfo.setId(fofId);
            fofInfo.setFullName(fofName);
            fofInfo.setShortName(fofName);
            fofInfoService.updateIgnoreNull(fofInfo);

            IntCodeResult saveParamResult = fofParamHistoyService.save(fofId,params);
            IntCodeResult intCodeResult = IntCodeResult.error("");
            if(saveParamResult.isSuccess()){
                intCodeResult = fofResultService.updateFofResult(fofId,params,Integer.parseInt(saveParamResult.getExtVal("paramHistoryId").toString()));
            }else{
                return Result.error("saveParamResult error",null);
            }

            if(!intCodeResult.isSuccess() || !saveParamResult.isSuccess()){
                return Result.setIntCodeResult(intCodeResult);
            }

        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("未知错误",null);
        }
        return Result.success(result);
    }

    @RequestMapping(value = "/deleteFof", name = "接口描述")
    @ResponseBody
    @IgnoreCookieAuth
    public Object deleteFof(Integer fofId,Integer uid) {
        FofInfo fofInfo = fofInfoService.fetchById(fofId);
        if(null == fofInfo){
            return Result.error("未查到此FOF",null);
        }
        if(uid!=fofInfo.getUserId()){
            return Result.error("不是您的FOF您无权删除",null);
        }
        fofInfoService.deleteFofInfo(fofId,uid);
        return Result.success("成功删除FOF");

    }
    @RequestMapping(value = "/changeStatus", name = "更改Fof可见性")
    @ResponseBody
    public Object changeStatus(int fofId,int status,
                               @RequestParam(defaultValue = "",required = false) String userIds){
        boolean success = fofInfoService.changeStatus(fofId,status);

        if(status == 3){
            if(StringUtil.isNoneBlank(userIds)){
                for(String userId : userIds.split(",")){
                    fofUserService.grantFof2User(fofId,Integer.parseInt(userId));
                }
            }
        }

        if(success){
            fofInfoService.reIndexUserFof();
            return Result.success();
        }else {
            return Result.error();
        }
    }

    @RequestMapping(value = "/startCreate", name = "点击创建的时候生成一个唯一的一个ID")
    @ResponseBody
    public Object startCreate(String uid) {
        String bid = LogUtil.getLogId();
        return Result.success().addDateItem("bid",bid);
    }

    @RequestMapping(value = "/getAssetOrStrategy", name = "接口描述")
    @ResponseBody
    public Object getAssetOrStrategy(Integer productTypeId) {
        Map<String, Object> result = null;
        try {
            ProductType productType = productTypeService.fetchById(productTypeId);
            String assetStrategyIds = productType.getAssetStrategyIds();

            List<AssetStrategyInfo> assetStrategyInfoList = assetStrategyInfoService.getAssetStrategyByIds(assetStrategyIds.split(","));

            List<Map<String, Object>> assetStrategyInfoMapList = new ArrayList<Map<String, Object>>();
            Map<String, Object> assetStrategyInfoItemMap = null;
            for (AssetStrategyInfo assetStrategyInfo : assetStrategyInfoList) {
                assetStrategyInfoItemMap = new HashMap<String, Object>();
                assetStrategyInfoItemMap.put("id", assetStrategyInfo.getId());
                assetStrategyInfoItemMap.put("assetStrategyId", assetStrategyInfo.getId());
                assetStrategyInfoItemMap.put("name", assetStrategyInfo.getName());
                assetStrategyInfoItemMap.put("type", assetStrategyInfo.getType());

                List<Benchmark> benchmarkList = benchmarkService.getBenchMarkByType(assetStrategyInfo.getId());
                if (null == benchmarkList) benchmarkList = new ArrayList<Benchmark>();
                assetStrategyInfoItemMap.put("benchMarkList", benchmarkList);

                assetStrategyInfoMapList.add(assetStrategyInfoItemMap);
            }
            result = new HashMap<String, Object>();
            result.put("assetStrategyInfoList", assetStrategyInfoMapList);
        } catch (Exception e) {
            LogUtil.errorLog(e, "");
            return Result.error();
        }
        return Result.success(result);
    }


    @RequestMapping(value = "/assetOrStrategyStart", name = "资产、策略配置开始计算接口")
    @ResponseBody
    public Object assetOrStrategyStart(@RequestParam(defaultValue = "1") int calType,
                                       String bizId,
                                       String params) {
        FofTask fofTask = fofTaskService.addTask(calType,params,bizId);

        String taskId = fofTask.getTaskId();

        new Thread(){
            private String taskId;

            public String getTaskId() {
                return taskId;
            }

            public Thread setTaskId(String taskId) {
                this.taskId = taskId;
                return this;
            }

            public void run(){
                LogUtil.debugLog("async task start");
                fofTaskService.startTask(taskId);
            }
        }.setTaskId(taskId).start();


        Map<String, Object> result = new HashedMap();
        result.put("taskId", taskId);
        return Result.success(result);
    }

    @RequestMapping(value = "/assetOrStrategyResult", name = "资产、策略配置结果")
    @ResponseBody
    public Object assetOrStrategyResult(String taskId) {
        int randomKey = new Random().nextInt(5);

        FofTask fofTask = fofTaskService.getTaskByTaskId(taskId);

        if(null == fofTask){
            return new Result(-3,"未查到任务",null);
        }

        if(fofTask.getStatus() == -1){
            return new Result(-2,fofTask.getMsg(),null);
        }

        if(fofTask.getStatus() == FofTask.TASK_STATUS.INIT.status()
                || fofTask.getStatus() == FofTask.TASK_STATUS.RUNNING.status()){
            return new Result(-1,"计算未结束",null);
        }

        File outputFile = null;
        if("site".equals(env.getProperty("spring.profiles.active"))){
            if(fofTask.getStatus() == FofTask.TASK_STATUS.SUCESS.status()){
                String resultPath = fofTask.getDataDir();
                taskId = fofTask.getTaskId();
                outputFile = new File(resultPath,taskId+"_Output.txt");
                if(null == outputFile || !outputFile.exists()){
                    return new Result(-2,"计算失败",null);
                }
            }
        }else{
            if(randomKey != 3){
                return new Result(-1,"计算未结束",null);
            }
            String classPath = this.getClass().getResource("/").getPath();
            outputFile = new File(classPath + File.separator + "others" + File.separator + "output.txt");
        }

        Map<String, Object> result = new HashedMap();
        List<Object> pointList = new ArrayList<Object>();
        try {
            TaskParams taskParams = fofTask.getTaskParams();
            String mouldId = taskParams.getModelId();
            List<String> lineList = FileUtil.readLines(outputFile, Charset.defaultCharset());
            if (null != lineList && lineList.size() >= 0) {
                int assetCount = getAssetCount(mouldId,lineList.get(0));
                List<String> assetNameList = getAssetNameArr(assetCount,fofTask);
                List<Object> itemList = null;
                Map<String, Object> assetProportion = null;
                for (String line : lineList) {
                    itemList = new ArrayList<Object>();
                    String[] assetArr = line.split("\t");
                    itemList.add(assetArr[assetArr.length - 1]);//X轴
                    itemList.add(assetArr[assetArr.length - 2]);//Y轴

                    assetProportion = new HashedMap();
                    for (int i = 0; i < assetCount; i++) {
                        if("3".equals(mouldId)){
                            if(assetNameList.get(i).contains("货币")){
                                continue;
                            }
                            assetProportion.put(assetNameList.get(i), assetArr[i+1]);
                        }else{
                            assetProportion.put(assetNameList.get(i), assetArr[i]);
                        }
                    }
                    if("3".equals(mouldId)){
                        assetProportion.put("现金",assetArr[0]);
                    }
                    itemList.add(assetProportion);
                    pointList.add(itemList);
                }
            }
        } catch (IOException e) {
            LogUtil.errorLog(e, "");
            return Result.error();
        }

        result.put("pointList", pointList);

        if(fofTask.getType()==1){
            result.put("benchMarkPriceTrend",benchmarkPriceService.getBenchMarkPriceTrendChart(fofTask));
        }else if(fofTask.getType() == 2){
            result.put("cov",fofTaskService.getCovResult(taskId));
            result.put("fundPriceTrend",fundNavService.getFundNavPriceTrendChart(fofTask));
        }

        return Result.success(result);
    }


    @RequestMapping(value = "/assetOrStrategyResultCustom", name = "资产、策略配置自定义权重结果")
    @ResponseBody
    public Object assetOrStrategyResultCustom(String taskId) {
        FofTask fofTask = fofTaskService.getTaskByTaskId(taskId);
        Map<String, Object> result = new HashedMap();
        if(fofTask.getType()==1){
            result.put("benchMarkPriceTrend",benchmarkPriceService.getBenchMarkPriceTrendChart(fofTask));
        }else if(fofTask.getType() == 2){
            if(null == fofTask){
                return new Result(-3,"未查到任务",null);
            }

            if(fofTask.getStatus() == -1){
                return new Result(-2,fofTask.getMsg(),null);
            }

            if(fofTask.getStatus() == FofTask.TASK_STATUS.INIT.status()
                    || fofTask.getStatus() == FofTask.TASK_STATUS.RUNNING.status()){
                return new Result(-1,"计算未结束",null);
            }

            result.put("fundPriceTrend",fundNavService.getFundNavPriceTrendChart(fofTask));
            result.put("cov",fofTaskService.getCovResult(taskId));
        }
        return Result.success(result);
    }

    private List<String> getAssetNameArr(int assetCount, FofTask fofTask) {
        List<String> assetNameList = new ArrayList<String>();
        String paramStr = fofTask.getParams();
        TaskParams taskParams = JsonUtil.parse(paramStr,TaskParams.class);

        if(fofTask.getType()==1){
            List<TaskParams.BenchmarkParamsBean> benchmarkParamsBeanList = taskParams.getBenchmarkParams();

            for(TaskParams.BenchmarkParamsBean param : benchmarkParamsBeanList){
                Integer id = param.getId();
                Benchmark benchmark = benchmarkService.fetchById(id);
                int assetStrategyId = benchmark.getAssetStrategyId();
                AssetStrategyInfo assetStrategyInfo = assetStrategyInfoService.fetchById(assetStrategyId);
                String name = assetStrategyInfo.getName();
                assetNameList.add(name);
            }
        }else if(fofTask.getType()==2){
            List<TaskParams.UpDownParamsBean> upDownParamsBeanList = taskParams.getUpDownParams();
            for(TaskParams.UpDownParamsBean item : upDownParamsBeanList){
                String extCode = item.getId();
                FundInfo fundInfo = fundInfoService.fetchById(extCode);
                if(null == fundInfo){
                    assetNameList.add("");
                }else{
                    assetNameList.add(fundInfo.getFundNameShort());
                }
            }
        }


        return assetNameList;
    }

    private int getAssetCount(String mouldId,String line) {
        int lineSeptCount = line.split("\\s+").length;
        if (lineSeptCount < 4) {
            return -1;
        }
        if("3".equals(mouldId)){//rp模型第一列为现金占比，多一列
            return lineSeptCount - 3;
        }
        return lineSeptCount - 2;
    }

    @RequestMapping(value = "/fundFilter", name = "基金筛选接口")
    @ResponseBody
    public Object fundFilter(@RequestParam(defaultValue = "2") Integer productType,
                             @RequestParam(defaultValue = "0") Integer fundType,//1表示万得(公募)，2表示朝阳永续(私募) 0 全部
                             @RequestParam(defaultValue = "0") Integer curAssetStrategyId,
                             @RequestParam(defaultValue = "") String key,//检索关键字
                             @RequestParam(defaultValue = "desc") String sortType,//desc 降序 asc 升序
                             @RequestParam(defaultValue = "sharpRatio") String sortName,//排序关键字
                             @RequestParam(defaultValue = "0") int all,//0：只返回正常数据 1:返回所有数据
                             @RequestParam(defaultValue = "") String list,//用户所选资产比例
                             @RequestParam(defaultValue = "") String bizId,//业务ID
                             @RequestParam(defaultValue = "",required = false) String manager,
                             @RequestParam(defaultValue = "",required = false) String management,
                             @RequestParam(defaultValue = "0") Integer uid,//当前用户的ID
                             @RequestParam(defaultValue = "1") Integer pn,
                             @RequestParam(defaultValue = "50") Integer rn) {

        Pagination fundPageList = fundInfoService.filterFundInfoByProductType(productType,fundType,curAssetStrategyId,
                key,sortType,sortName,all,manager,management,uid,pn,rn);
        fundInfoService.updateCollectStatus(fundPageList,uid);
        fofTaskService.setFofTaskAssetStrategyResult(bizId,list);
        return Result.success(fundPageList);
    }

    @RequestMapping(value = "/viewPointCal", name = "Black-Litterman(BL)模型中性值计算")
    @ResponseBody
    public Object viewPointCal(String benchmarkIds,
                               int traceYearLengthParam){
        String[] benchmarkIdArr = benchmarkIds.split(",");

        List<Map<String,Object>> viewPointResult = new ArrayList<Map<String,Object>>();

        Map<String,Object> benchmarkViewPointMap = null;
        Double yield = 0.0;
        for(String benchmarkId : benchmarkIdArr){
            benchmarkViewPointMap = new HashedMap();
            Benchmark benchmark = benchmarkService.fetchById(Long.valueOf(benchmarkId));
            FundInfo fundInfo = fundInfoService.fetchById(benchmark.getWindCode());
            if(null != fundInfo){
                if(traceYearLengthParam == 1){
                    yield = fundInfo.getYield1y();
                }else if(traceYearLengthParam == 2){
                    yield = fundInfo.getYield3y();
                }else if(traceYearLengthParam == 3){
                    yield = fundInfo.getYield5y();
                }
            }

            benchmarkViewPointMap.put("benchmarkId",benchmarkId);
            benchmarkViewPointMap.put("yield",yield);
            viewPointResult.add(benchmarkViewPointMap);
        }

        Map<String,Object> resultMap = new HashedMap();
        resultMap.put("result",viewPointResult);
        return Result.success(resultMap);
    }


    @RequestMapping(value = "/fundsTrend", name = "基金净值走势")
    @ResponseBody
    public Object fundsTrend(String fundIds,
                             @RequestParam(defaultValue = "0") int year){
        Date endDate = DateUtil.nowAsDate();
        Date startDate = null;
        if(year>0){
            startDate = DateUtil.add(endDate,-year*365*24*60*60);
        }
        String[] fundIdArr = fundIds.split(",");
        List<Map<String,Object>> fundsTrendMapList = fundNavService.getFundsTrendByDateRange(fundIdArr,startDate,endDate);
        return Result.success().addDateItem("priceList",fundsTrendMapList);
    }

    @RequestMapping(value = "/serviceStatus", name = "监控服务状态")
    @ResponseBody
    @IgnoreCookieAuth
    public Object serviceStatus() {
        return Result.success();
    }


}
